using System;
using System.Collections.Generic;
using UnityEngine;
using Object = UnityEngine.Object;

namespace Jerry.UiFrame
{
    public class UIManager
    {
        private static UIManager _instance;
        private static string _path = "";
        private static Canvas _canvas;
        private static Camera _camera;

        public static UIManager Instance
        {
            get
            {
                if (_instance == null)
                {
                    _instance = new UIManager();
                    _path = Resources.Load<AllPaths>("UiPathConfig").prefabPath.Replace("Assets/Resources/", "");
                }

                return _instance;
            }
        }

        #region UI设置相关

        /// <summary>
        /// 
        /// </summary>
        internal static Canvas Canvas
        {
            get
            {
                if (!_canvas)
                {
                    var asset = Resources.Load<GameObject>("2DCanvas");
                    var go = Object.Instantiate(asset);
                    go.name = "2DCanvas";
                    Object.DontDestroyOnLoad(go);
                    _canvas = go.transform.Find("Canvas").GetComponent<Canvas>();
                }

                return _canvas;
            }
        }

        internal static Camera UICamera
        {
            set
            {
                if (value)
                {
                    _camera = value;
                    Canvas.worldCamera = _camera;
                    Canvas.transform.parent.Find("UICamera").gameObject.SetActive(false);
                }
            }
            get
            {
                if (!_camera)
                    _camera = Canvas.worldCamera;
                return _camera;
            }
        }

        internal static AudioSource AudioSource => Canvas.transform.parent.GetComponentInChildren<AudioSource>();

        #endregion

        private readonly Dictionary<string, UIBase> _activeWindows = new();

        private int _index = -1; //控制界面

        /// <summary>
        /// 打开界面
        /// </summary>
        /// <param name="bStay">是否常驻</param>
        /// <param name="p"></param>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public T OpenWindow<T>(bool bStay = false, params object[] p) where T : UIBase
        {
            _index++;
            var winName = typeof(T).Name;
            UIBase win = GetWindow(winName);
            if (!win)
            {
                win.ReceiveParams(p);
                var prefab = UIConfig.GetLoader().LoadExternal<GameObject>(_path + winName);
                var go = Object.Instantiate(prefab);
                win = go.AddComponent<T>();
                win.WinName = winName;
                win.Priority = bStay ? int.MaxValue : _index;
                _activeWindows.Add(winName, win);
                CheckUiCount();
            }
            else
            {
                win.Priority = bStay ? int.MaxValue : _index;
                win.ReceiveParams(p);
                win.gameObject.SetActive(true);
                win.gameObject.transform.SetAsLastSibling();
            }

            return (T)win;
        }

        /// <summary>
        /// 打开窗口
        /// </summary>
        /// <param name="p"></param>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public T OpenWindow<T>(params object[] p) where T : UIBase
        {
            _index++;
            var winName = typeof(T).Name;
            UIBase win = GetWindow(winName);
            if (!win)
            {
                var prefab = UIConfig.GetLoader().LoadExternal<GameObject>(_path + winName);
                var go = Object.Instantiate(prefab);
                win = go.AddComponent<T>();
                win.ReceiveParams(p);
                win.EnableComponent();
                win.WinName = winName;
                win.Priority = _index;
                _activeWindows.Add(winName, win);
                CheckUiCount();
            }
            else
            {
                win.ReceiveParams(p);
                win.Priority = _index;
                win.gameObject.SetActive(true);
                win.gameObject.transform.SetAsLastSibling();
            }

            return (T)win;
        }

        /// <summary>
        /// 关闭窗口
        /// </summary>
        /// <typeparam name="T"></typeparam>
        public void CloseWindow<T>() where T : UIBase
        {
            var winName = typeof(T).Name;
            UIBase win = GetWindow(winName);
            if (win)
            {
                win.CloseWindow();
            }
        }

        /// <summary>
        /// 销毁界面
        /// </summary>
        /// <typeparam name="T"></typeparam>
        [Obsolete("框架会自动销毁界面，谨慎手动调用此方法")]
        public void DestroyWindow<T>() where T : UIBase
        {
            var winName = typeof(T).Name;
            UIBase win = GetWindow(winName);
            {
                win.DestroyWindow();
                //从保存列表中移除
                _activeWindows.Remove(winName);
            }
        }

        /// <summary>
        /// 销毁所有界面
        /// 慎用
        /// </summary>
        public void DestroyAllWindow()
        {
            foreach (var item in _activeWindows)
            {
                item.Value.DestroyWindow();
            }
            
            _activeWindows.Clear();
        }

        /// <summary>
        /// 获取已经打开的窗口
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <returns></returns>
        public T GetWindow<T>() where T : UIBase
        {
            var winName = typeof(T).Name;
            return GetWindow(winName) as T;
        }

        internal void CloseWindow(string winName)
        {
            UIBase win = GetWindow(winName);
            if (win)
            {
                win.gameObject.SetActive(false);
            }

            int maxIndex = int.MinValue;
            UIBase toReActive = null;
            foreach (var item in _activeWindows)
            {
                if (item.Key == winName) continue;
                if (!item.Value.gameObject.activeSelf) continue;
                if (item.Value.Priority > maxIndex)
                {
                    maxIndex = item.Value.Priority;
                    toReActive = item.Value;
                }
            }

            toReActive?.ReActivate();
        }

        /// <summary>
        /// 获取窗口
        /// </summary>
        /// <param name="winName"></param>
        /// <returns></returns>
        private UIBase GetWindow(string winName)
        {
            return _activeWindows.GetValueOrDefault(winName);
        }

        /// <summary>
        /// 保证界面不超过最大的缓存量
        /// </summary>
        private void CheckUiCount()
        {
            if (_activeWindows.Count > UIConfig.MaxExistWindows)
            {
                UIBase toRemove = null;
                int min = int.MaxValue;
                foreach (var win in _activeWindows)
                {
                    if (win.Value.Priority < min)
                    {
                        min = win.Value.Priority;
                        toRemove = win.Value;
                    }
                }

                if (toRemove != null)
                {
                    // Debug.Log($"移出{toRemove.Priority}    {toRemove.WinName}");
                    _activeWindows.Remove(toRemove.WinName);
                    toRemove.DestroyWindow();
                }
            }
        }
    }
}